package rwtxt

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"gitee.com/zht639/my_gopkg/strtrans"
)

// ReadFromAllTXT 读取指定文件夹下的所有 .txt 文件，并将每个文件解析为结构体切片，最终返回一个二维切片
func ReadFromAllTXT[T any](folderPath string) ([][]T, error) {
	// 确保 T 是一个结构体
	var zero T
	structType := reflect.TypeOf(zero)
	if structType.Kind() != reflect.Struct {
		return nil, fmt.Errorf("传入的泛型必须是一个结构体")
	}

	// 创建一个二维切片来存储所有文件的结构体切片
	var allData [][]T

	// 打开指定的目录
	files, err := os.ReadDir(folderPath)
	if err != nil {
		return nil, err
	}

	// 遍历目录中的所有文件
	for _, file := range files {
		// 仅处理 .txt 文件
		if !strings.HasSuffix(file.Name(), ".txt") {
			continue
		}

		// 获取文件的完整路径
		filePath := filepath.Join(folderPath, file.Name())

		// 调用 ReadFromTXT 函数读取当前文件的数据
		fileData, err := ReadFromTXT[T](filePath)
		if err != nil {
			return nil, fmt.Errorf("读取文件 %s 失败: %v", filePath, err)
		}

		// 将每个文件的一维切片添加到二维切片中
		allData = append(allData, fileData)
	}

	return allData, nil
}

// ReadFromTXT 读取文件并将数据解析为结构体切片
// 注意，假设每行字段以空格分隔
func ReadFromTXT[T any](filepath string) ([]T, error) {
	// 确保 T 是一个结构体
	var zero T
	structType := reflect.TypeOf(zero)
	if structType.Kind() != reflect.Struct {
		return nil, fmt.Errorf("传入的泛型必须是一个结构体")
	}

	// 创建一个切片来存储结构体实例
	sliceType := reflect.SliceOf(structType)
	sliceValue := reflect.MakeSlice(sliceType, 0, 0)

	// 打开文件
	file, err := os.Open(filepath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)

	// 逐行读取文件内容
	for scanner.Scan() {
		line := scanner.Text()
		parts := strings.Split(line, " ") // 假设用空格分隔

		// 创建新的结构体实例
		elem := reflect.New(structType).Elem()

		// 遍历结构体字段并填充值
		for i := 0; i < elem.NumField(); i++ {
			field := elem.Field(i)
			if !field.CanSet() {
				continue
			}

			// 获取文件中的值
			if i >= len(parts) {
				break // 如果部分值不够，停止赋值
			}
			val := parts[i]

			// 根据字段类型设置值
			switch field.Kind() {
			case reflect.String:
				field.SetString(val)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				intVal, _ := strtrans.ToInt(val)
				field.SetInt(int64(intVal)) // 将 int 系列转换为 int
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				uintVal, _ := strtrans.ToInt(val)
				field.SetUint(uint64(uintVal)) // 将 uint 系列转换为 uint
			case reflect.Float32, reflect.Float64:
				floatVal, _ := strtrans.ToFloat(val)
				field.SetFloat(floatVal)
			case reflect.Bool:
				boolVal, _ := strtrans.ToBool(val)
				field.SetBool(boolVal)
			default:
				return nil, fmt.Errorf("不支持的字段类型: %s", field.Kind())
			}
		}

		// 将新的结构体实例添加到切片中
		sliceValue = reflect.Append(sliceValue, elem)
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	// 将 sliceValue 转换为 []T 类型并返回
	return sliceValue.Interface().([]T), nil
}

// Save2TXT 将结构体切片保存到文本文件，假设每行字段以空格分隔
func Save2TXT[T any](filepath string, my []T) error {
	file, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer file.Close()

	for _, item := range my {
		elem := reflect.ValueOf(item)
		if elem.Kind() != reflect.Struct {
			return fmt.Errorf("每个元素必须是结构体")
		}

		// 遍历结构体字段并写入文件
		var parts []string
		for i := 0; i < elem.NumField(); i++ {
			field := elem.Field(i)
			// 根据字段类型获取值
			var value string
			switch field.Kind() {
			case reflect.String:
				value = field.String()
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				value = strtrans.ToString(field.Int())
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				value = strtrans.ToString(field.Uint())
			case reflect.Float32, reflect.Float64:
				value = strtrans.ToString(field.Float())
			case reflect.Bool:
				value = strtrans.ToString(field.Bool())
			default:
				return fmt.Errorf("不支持的字段类型: %s", field.Kind())
			}
			parts = append(parts, value)
		}
		_, err := fmt.Fprintln(file, strings.Join(parts, " ")) // 写入一行
		if err != nil {
			return err
		}
	}

	return nil
}
